package org.snlab.compiler;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.Multigraph;

public class Topology {
    private Graph<Device, Link> graph = new Multigraph<>(Link.class);

    private Map<String, Device> nameToDevice = new HashMap<>();

    public static Topology fromFile(String fn) {
        Topology topology = new Topology();
        File f = new File(fn);
        Scanner in = null;
        try {
            in = new Scanner(f);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        while (in.hasNextLine()) {
            String line = in.nextLine();
            String[] tokens = line.split(" ");
            Device dev1 = topology.addDeviceByName(tokens[0]);
            Device dev2 = topology.addDeviceByName(tokens[2]);
            Link link = new Link(dev1, tokens[1], dev2, tokens[3]);
            topology.getGraph().addEdge(dev1, dev2, link);
        }

        System.out.println(topology.getGraph().edgeSet().size());
        System.out.println(topology.getGraph().vertexSet().size());
        return topology;
    }

    public Device addDeviceByName(String name) {
        if (!this.nameToDevice.containsKey(name)) {
            Device device = new Device(name);
            this.graph.addVertex(device);
            this.nameToDevice.put(name, device);
        }
        return this.nameToDevice.get(name);
    }

    public Device getDeviceByName(String name) {
        return this.nameToDevice.get(name);
    }

    public void addDevice(Device device) {
        this.graph.addVertex(device);
    }

    public void assignAddrFromFile(String fn) {
        DdmdConfs ddmdConfs = new DdmdConfs();
        ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
        try {
            ddmdConfs = objectMapper.readValue(new File(fn), DdmdConfs.class);
            for (DdmdConf ddmdConf : ddmdConfs.getDdmdConfs()) {
                this.nameToDevice.get(ddmdConf.getName()).setAddr("localhost:" + ddmdConf.getPort());
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * @return Graph<Device, Link> return the graph
     */
    public Graph<Device, Link> getGraph() {
        return graph;
    }

    /**
     * @param graph the graph to set
     */
    public void setGraph(Graph<Device, Link> graph) {
        this.graph = graph;
    }

}

class Link {
    private Map<Device, String> deviceToPort = new HashMap<>();

    public Link(Device dev1, String p1, Device dev2, String p2) {
        this.deviceToPort.put(dev1, p1);
        this.deviceToPort.put(dev2, p2);
    }

    public Map<Device, String> getDeviceToPort() {
        return this.deviceToPort;
    }

    public String getPort(Device device) {
        return this.deviceToPort.get(device);
    }
}
